/**
 * index_iterator.cpp
 */
#include "storage/index/index_iterator.h"
#include <cassert>
#include <cstddef>
#include "common/config.h"
#include "common/exception.h"
#include "storage/page/b_plus_tree_page.h"
#include "storage/page/page_guard.h"

namespace bustub {

/*
 * NOTE: you can change the destructor/constructor method here
 * set your own input parameters
 */
INDEX_TEMPLATE_ARGUMENTS
INDEXITERATOR_TYPE::IndexIterator() = default;

INDEX_TEMPLATE_ARGUMENTS
INDEXITERATOR_TYPE::~IndexIterator() {
  bpm_ = nullptr;
  cur_index_ = -1;
  page_id_ = INVALID_PAGE_ID;
}  // NOLINT

INDEX_TEMPLATE_ARGUMENTS
INDEXITERATOR_TYPE::IndexIterator(page_id_t page_id, int cur_index, BufferPoolManager *bpm)
    : bpm_(bpm), page_id_(page_id), cur_index_(cur_index) {}

INDEX_TEMPLATE_ARGUMENTS
auto INDEXITERATOR_TYPE::IsEnd() -> bool { return page_id_ == INVALID_PAGE_ID; }

INDEX_TEMPLATE_ARGUMENTS
auto INDEXITERATOR_TYPE::operator*() -> const MappingType & {
  if (IsEnd()) {
    throw Exception("Dereferencing End() iterator");
  }
  ReadPageGuard read_guard = bpm_->FetchPageRead(page_id_);
  auto page = read_guard.As<B_PLUS_TREE_LEAF_PAGE_TYPE>();
  return page->ItemAt(cur_index_);
}

INDEX_TEMPLATE_ARGUMENTS
auto INDEXITERATOR_TYPE::operator++() -> INDEXITERATOR_TYPE & {
  if (IsEnd()) {
    throw Exception("Increasing End() iterator");
  }
  ++cur_index_;
  ReadPageGuard read_guard = bpm_->FetchPageRead(page_id_);
  auto page = read_guard.As<B_PLUS_TREE_LEAF_PAGE_TYPE>();
  if (cur_index_ == page->GetSize()) {
    cur_index_ = 0;
    page_id_t next_page_id = page->GetNextPageId();

    if (next_page_id == INVALID_PAGE_ID) {
      bpm_ = nullptr;
      page_id_ = INVALID_PAGE_ID;
      cur_index_ = -1;
      return *this;
    }
    page_id_ = next_page_id;
  }
  return *this;
}

template class IndexIterator<GenericKey<4>, RID, GenericComparator<4>>;

template class IndexIterator<GenericKey<8>, RID, GenericComparator<8>>;

template class IndexIterator<GenericKey<16>, RID, GenericComparator<16>>;

template class IndexIterator<GenericKey<32>, RID, GenericComparator<32>>;

template class IndexIterator<GenericKey<64>, RID, GenericComparator<64>>;

}  // namespace bustub
